package fpzhan.plane.program.param;

import fpzhan.plane.program.util.StringUtils;
import fpzhan.plane.program.exception.ExecuteParamToolException;
import fpzhan.plane.program.function.CodeBlockObjectFunction;
import fpzhan.plane.program.function.ConditionFunction;

import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;

public final class ConditionParamTool<T> extends ParamTool<T> {


    protected ConditionParamTool(String getKey, Supplier<T> supplier) throws ExecuteParamToolException {
        super(getKey, supplier);
    }

    public ConditionParamTool(String getKey, ParamTool<T>.Operate operate) {
        super(getKey, operate);
    }

    @Override
    protected CodeBlockObjectFunction end() {
        return param -> {
            Object obj;
            int j=0;
            if (getKey!=null){
                obj=param.get(getKey);
            }else{
                obj=((Supplier)operate.getChains().get(0)).get();
                j++;
            }
            for(int i=j;i<operate.getChains().size();i++){
                if(Supplier.class.getName().equals(operate.getFunctionTypes().get(i))){
                    obj=((Supplier)operate.getChains().get(i)).get();
                }else if(Function.class.getName().equals(operate.getFunctionTypes().get(i))){
                    obj=((Function)operate.getChains().get(i)).apply(obj);
                }else if (BiFunction.class.getName().equals(operate.getFunctionTypes().get(i))){
                    if(StringUtils.isNotEmpty(operate.getLinks().get(i))){
                        obj=((BiFunction)operate.getChains().get(i)).apply(obj,param.get(operate.getLinks().get(i)));
                    }else{
                        obj=((BiFunction)operate.getChains().get(i)).apply(obj,operate.getParams().get(i));
                    }
                }
            }
            return obj;
        };
    }


    public <E >  ConditionFunction compare(BiFunction<T,E,Boolean> compare,E object){
        return param -> compare.apply((T)end().apply(param),(E)object);
    }



    public  ConditionFunction compare(Function<T,Boolean> compare){
        return param -> compare.apply((T)end().apply(param));
    }

    @Override
    public <E> ConditionParamTool<E> then(Function<T, E> function) {
        getOperate().add(Function.class.getName(),function,null);
        return new ConditionParamTool<E>(getKey,(ParamTool<E>.Operate)getOperate());
    }

    @Override
    public <R, E> ConditionParamTool<E> then(BiFunction<T, R, E> biFunction, R r) {
        getOperate().add(BiFunction.class.getName(),biFunction,r);
        return new ConditionParamTool<E>(getKey,(ParamTool<E>.Operate)getOperate());
    }

    @Override
    public <E, R> ConditionParamTool<E> thenLink(BiFunction<T, R, E> biFunction, String key) {
        getOperate().add(BiFunction.class.getName(),biFunction,null,key);
        return new ConditionParamTool<E>(getKey,(ParamTool<E>.Operate)getOperate());
    }
}

